﻿using System;
using System.Linq.Expressions;
using System.Reflection;

namespace AddressManager.Common.Extension
{
    /// <summary>
    /// Provides some useful extension methods for <see cref="object"/>s.
    /// </summary>
    public static class ObjectExtensions
    {
        /// <summary>
        /// Extracts the property name of an expression.
        /// Example: ExtractPropertyName(objectWithPropertyIsDiry, x => x.IsDirty) will return "IsDirty"
        /// </summary>
        public static string ExtractPropertyName<TSource, TProperty>(this TSource source, Expression<Func<TSource, TProperty>> propertyExpression)
        {
            var me = propertyExpression.Body as MemberExpression;

            if (me == null)
            {
                throw new ArgumentException(string.Format("Expression '{0}' refers to a method, not a property.", propertyExpression));
            }

            var propInfo = me.Member as PropertyInfo;
            if (propInfo == null)
            {
                throw new ArgumentException(string.Format("Expression '{0}' refers to a field, not a property.", propertyExpression));
            }

            return me.Member.Name;
        }

        /// <summary>
        /// Evaluates the value of the property with the given name.
        /// </summary>
        public static object GetPropertyValue<T>(this T o, string propertyName)
        {
            Type type = typeof(T);
            PropertyInfo propInfo = type.GetProperty(propertyName, BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Public | BindingFlags.Static);
            if (propInfo == null)
            {
                throw new ArgumentException(String.Format("Type {0} has no property named '{1}'.", type, propertyName));
            }
            return propInfo.GetValue(o, null);
        }
    }
}